/*
    Estado        Metodo
    Sin P       insertarCarrito
 */

package dal;

import bd.BoundParam;
import bd.ConexionAvw;

import excepciones.AvwException;

import java.sql.PreparedStatement;
import java.sql.ResultSet;

import java.sql.SQLException;
import static java.sql.Types.*;

import java.util.ArrayList;
import java.util.Calendar;

import java.util.logging.Level;
import java.util.logging.Logger;

import negocio.ArticuloWeb;
import negocio.CarritoArticuloWeb;
import negocio.CarritoWeb;
import negocio.Cliente;
import util.Email;
import util.Recurso;

import util.Utiles;

public class CarritoDAL {

    static final Logger logger = Utiles.iniciarLogger("CarritoDAL", true);
    
    public CarritoDAL() {
    }

    /**
     * Guarda el objeto CarritoWeb pasado por paremtro.
     * (ver detalle en documentacion)
     * @param carritoWeb CarritoWeb con el objeto ClienteWeb y 
     * un array de objetos CarritoArticuloWeb que contienen 
     * el objeto ArticuloCamapania.
    1. Se debe buscar cual es el numero del comprobante, para ello vamos 
    a la tabla NUMERADORES_COMPROBANTES en donde filtramos por 
    NUC_CODIGO = "PRVA" o "PRVB" en funcion si es un presupuesto tipo A o B. 
    En el campo NUC_VALOR encontramos cual es el proximo numero de comprobante. 
    RECORDAR que es necesario incrementar en uno este campo NUC_VALOR.
    
    2. Se debe generar un registro en la tabla COMPROBANTES:
    TCO_CODIGO: PRVA - PRVB en funsion si es un presupuesto tipo A o B.
    COM_NUMERO: El numero de comprobante que calculamos en el punto 1.
    COM_FECHA_EMISION: Viene en el campo fecha del objeto CarritoWeb.
    COM_IMPORTE: Viene en el campo importe del objeto CarritoWeb.
    COM_TIPO_IVA: RI - CF en funsion si es un presupuesto A o B.
    
    3. Para cada detalle del carrito se genera un registro en la tabla COMPROBANTES_ARTICULOS:
    COM_CODIGO: Codigo del comprobante.
    ART_CODIGO: Codigo del articulo.
    CMA_CANTIDAD: Cantidad de articulos.
    CMA_IMPORTE: Importe.
    
    4. Tambien, por cada detalle del carrito se genera un registro en la tabla
    COMPROBANTES_CONCEPTOS:
    COM_CODIGO: Codigo del comprobante.
    TCN_CODIGO: GE21 - Gasto de envio.
    COC_CANTIDAD: Cantidad de articulos.
    COC_IMPORTE: Costo de envio del articulo.
     */
    public static String insertarCarrito(CarritoWeb carritoWeb) throws AvwException {
        ArrayList arr = new ArrayList();
        StringBuilder sql = new StringBuilder();
        ResultSet rs;
        ConexionAvw conexion = new ConexionAvw();
        ArrayList params = new ArrayList();
        int pos =0;
        
        logger.info("Integer cantArticulos lo utilizo para acumular la cantidad de articulos");
        logger.info("Float costoEnvio lo utilizo para acumular el gasto de envio");
        Integer cantArticulos = 0; 
        float costoEnvio = 0; 
        
        String comNumero;
        String comCodigo;
        //Campos a insertar hardcode
        String tipoPresupuesto = "PRVB";//Se especifica el codigo del tipo de presupuesto TCO_CODIGO que se inserta en COMPROBANTES
        String tipoIva = "CF";// Se especifica el codigo del tipo iva TIPO_IVA (consumidor final) que se inserta en COMPROBANTES
        String comEstado = "PENDIENTE"; // Se especifica el codigo de estado COM_ESTADO que se inserta en COMPROBANTES 
        String usuCodigo = "USUARIO_WEB";//Se especifica el codigo de usuario USU_CODIGO que va a ser insertado en COMPROBANTES
        String centroCosto = "CALLCENTER";//Se especifica el centro de costo CEN_CODIGO que se inserta en COMPROBANTES
        String sucursalCodigo = "ventatelef"; //Se especifica el codigo de la sucursal SUC_CODIGO que se inserta en COMPROBANTES
        String tipoPago = "CTD";//Se especifica el codigo de tipo de pago COP_CODIGO que se inserta en  COMPROBANTES
        String depositoCodigo = "12"; //Se especifica el codigo del deposito DEP_CODIGO que se inserta en COMPROBANTES
        String conceptoCodigo = "GE21"; //Se especifica el codigo concepto es decir el codigo del costo de envio TCN_CODIGO que se inserta en COMPROBANTES_CONCEPTOS 
        
        try {
             //obtengo el numero del comprobante.
            comNumero = getNucValor(tipoPresupuesto);
            //incremento en uno el valor del comprobante
            incrementarNucValor(tipoPresupuesto);

            conexion.abrirConexion();
            conexion.startTransaction();
            //Genero el comprobante
            logger.info("Inserto en comprobantes");
            sql.setLength(0);//Limpio el StringBuilder
            sql.append("INSERT INTO comprobantes (cam_codigo, suc_codigo, ");
            sql.append("dep_codigo, tco_codigo, com_numero, ");
            sql.append("com_importe, com_tipo_iva, usu_codigo, com_estado, ");
            sql.append("cli_codigo, com_razon_social, cen_codigo, cop_codigo, com_fecha_emision)");
            sql.append("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,sysdate)");
 
            params.add(new BoundParam(++pos,Utiles.noNull(carritoWeb.getCrwCampania().getCamCodigo()),VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(sucursalCodigo),VARCHAR,true));
            params.add(new BoundParam(++pos,Utiles.noNull(depositoCodigo),VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(tipoPresupuesto),VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(comNumero),VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(carritoWeb.getCrwImporte()), FLOAT));
            params.add(new BoundParam(++pos,Utiles.noNull(tipoIva), VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(usuCodigo), VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(comEstado), VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(carritoWeb.getCrwCliente().getCliCodigo()), VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(carritoWeb.getCrwCliente().getCliNombre()), VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(centroCosto), VARCHAR));
            params.add(new BoundParam(++pos,Utiles.noNull(tipoPago), VARCHAR));
            
            Calendar calendar = Calendar.getInstance();
            
            String fecha = calendar.get(calendar.DAY_OF_MONTH) + "/" + calendar.get(calendar.MONTH) + "/" + calendar.get(calendar.YEAR);
            
            logger.info(    " CAM_CODIGO: " +carritoWeb.getCrwCampania().getCamCodigo()+
                            " SUC_CODIGO: " +sucursalCodigo+
                            " DEP_CODIGO: " +depositoCodigo+
                            " TCO_CODIGO: "+tipoPresupuesto+
                            " COM_NUMERO: " +comNumero+ 
                            " COM_IMPORTE: " + carritoWeb.getCrwImporte()+ 
                            " COM_TIPO_IVA: " + tipoIva+ 
                            " USU_CODIGO: " + usuCodigo+ 
                            " COM_ESTADO: " + comEstado+ 
                            " CLI_CODIGO: " +carritoWeb.getCrwCliente().getCliCodigo()+
                            " COM_RAZON_SOCIAL: " +carritoWeb.getCrwCliente().getCliNombre()+
                            " CEN_CODIGO: " +centroCosto+
                            " COP_CODIGO: " +tipoPago+
                            " COM_FECHA_EMISION: " + fecha);
            conexion.executePreparedStatement(sql, params);
            
            //obtengo el codigo del comprobante
            sql.setLength(0); //Limpio la cadena
            String consulta = new Recurso("consultas.properties").obtenerPropiedad("consultaGetComCodigo");
            //Busco en un consultas.properties la consulta que obtiene el codigo de comprobante recien ingresado
            sql.append(consulta);
            
            logger.info("Busco el com_codigo");
            rs = conexion.getPreparedStatementResultSet(sql, null);
            logger.info(consulta);
            rs.next();
            comCodigo = Utiles.noNull(rs.getObject(1));

            //Genero los comprobantes articulos
            sql.setLength(0);//Limpio la cadena
            pos=0;
            sql.append("INSERT INTO comprobantes_articulos ( ");
            sql.append("com_codigo, art_codigo, cma_cantidad, ");
            sql.append("cma_cantidad_pendiente, cma_importe, cma_importe_bruto) ");
            sql.append("VALUES (?,?,?,?,?,?)");
            
            for (CarritoArticuloWeb caw: carritoWeb.getCrwCarritoArticulo()) {
                logger.info("Agrego un comprobante articulo");
                logger.info("COM_CODIGO:"+comCodigo +" ART_CODIGO: " + 
                            caw.getCawArticuloCampania().getArcArticulo().getArtCodigo() + 
                            "CMA_CANTIDAD: " + caw.getCawCantidad() + 
                            "CMA_CANTIDAD_PENDIENTE"+caw.getCawCantidad()+
                            "CMA_IMPORTE: " + caw.getCawPrecio()+
                            "CMA_IMPORTE_BRUTO: " + caw.getCawArticuloCampania().getArcPrecioDescuentoBruto());
                
                pos =0;//Posiciones de los parametros
                params.clear();//Limpio el arrayList de parametros
                
                String precioNeto = Utiles.noNull(caw.getCawArticuloCampania().getArcPrecioDescuento());
                precioNeto.replace(".",",");
                String precioBruto = Utiles.noNull(caw.getCawArticuloCampania().getArcPrecioDescuentoBruto());
                precioBruto.replace(".",",");
                
                params.add(new BoundParam(++pos, Utiles.noNull(comCodigo),NUMERIC));
                params.add(new BoundParam(++pos,Utiles.noNull(caw.getCawArticuloCampania().getArcArticulo().getArtCodigo()), VARCHAR));
                params.add(new BoundParam(++pos, Utiles.noNull(caw.getCawCantidad()), NUMERIC));
                params.add(new BoundParam(++pos, Utiles.noNull(caw.getCawCantidad()), NUMERIC));
                params.add(new BoundParam(++pos, precioNeto, FLOAT));/*Este es el precio neto  unitario de este articulo */
                params.add(new BoundParam(++pos, precioBruto, FLOAT));/*Este es el precio bruto unitario de este articulo */
                
                logger.info(sql.toString().toUpperCase());
                
                conexion.executePreparedStatement(sql, params);
            }
            
            //Limpio el StringBuilder
            sql.setLength(0);
            pos=0;
            //Genero los comprobantes conceptos
            sql.append("INSERT INTO comprobantes_conceptos( ");
            sql.append("com_codigo, coc_cantidad, coc_cantidad_pendiente, "); 
            sql.append("coc_importe, tcn_codigo) "); 
            sql.append("VALUES (?,?,?,?,?)");
            for (CarritoArticuloWeb caw: carritoWeb.getCrwCarritoArticulo()) {
                
                logger.info("Agrego un comprobante concepto");
                logger.info("COM_CODIGO: "+comCodigo+" COC_CANTIDAD: " + 
                        caw.getCawCantidad()+ " COC_CANTIDAD_PENDIENTE: "+ 
                        caw.getCawCantidad()+ "COC_IMPORTE: " + costoEnvio +
                        "TCN_CODIGO:" + conceptoCodigo);
                        
                if (caw.getCawArticuloCampania().getArcArticulo().getArtCostoEnvio()!=0){
                    pos =0;//Posiciones de los parametros
                    params.clear();//Limpio el arrayList de parametros
                    String precio = Utiles.noNull(caw.getCawArticuloCampania().getArcArticulo().getArtCostoEnvio());
                    precio.replace(".",",");

                    params.add(new BoundParam(++pos, Utiles.noNull(comCodigo), NUMERIC));
                    params.add(new BoundParam(++pos, Utiles.noNull(caw.getCawCantidad()), NUMERIC));//Cantidad de articulos pedidos
                    params.add(new BoundParam(++pos, Utiles.noNull(caw.getCawCantidad()), NUMERIC));//Cantidad pendiente de articulos pedidos
                    params.add(new BoundParam(++pos,precio,FLOAT));//Este es el precio de envio del articulo
                    params.add(new BoundParam(++pos, conceptoCodigo, VARCHAR));

                    logger.info(sql.toString().toUpperCase());

                    conexion.executePreparedStatement(sql, params);
                }
            }
            conexion.commitTransaction();
            StringBuilder mensaje = new StringBuilder();
            mensaje.append("Se realizo una nueva compra, con el comprobante COM_CODIGO: " + comCodigo + "\n");
            mensaje.append(" --NUC_VALOR: " + comNumero + "\n");
            mensaje.append(" --CAM_CODIGO: " + carritoWeb.getCrwCampania().getCamCodigo()+ "\n");
            mensaje.append(" --COM_IMPORTE: " + carritoWeb.getCrwImporte()+ "\n");
            mensaje.append(" --CLI_CODIGO: " + carritoWeb.getCrwCliente().getCliCodigo()+ "\n");
            mensaje.append(" --CLI_NOMBRE: " + carritoWeb.getCrwCliente().getCliNombre()+ "\n");
            mensaje.append(" --COM_FECHA_EMISION: " + fecha+ "\n");
            mensaje.append(" --COM_IMPORTE: " + carritoWeb.getCrwImporte() + "//Importe total del carrito"+ "\n");
            mensaje.append(" --ARTICULOS COMPRADOS: "+ "\n" );
            for (CarritoArticuloWeb caw: carritoWeb.getCrwCarritoArticulo()) {
                mensaje.append(" ----ART_CODIGO: " + caw.getCawArticuloCampania().getArcArticulo().getArtCodigo()+ "\n");
                mensaje.append(" ----ART_CANTIDAD: " + caw.getCawCantidad()+ "\n");
                mensaje.append(" ----ART_IMPORTE: " + caw.getCawPrecio() + "//Cantidad * importe"+ "\n");
                mensaje.append(" ----ART_IMPORTE_BRUTO: " + caw.getCawArticuloCampania().getArcPrecioDescuentoBruto()+ "\n");
                mensaje.append(" ----COSTO_ENVIO: " + Utiles.noNull(caw.getCawArticuloCampania().getArcArticulo().getArtCostoEnvioBruto())+ "\n");
            }
            String titulo = "se realizo una venta web";
            Email email = new Email();
            Recurso r = new Recurso("mail.properties");
            String mail = r.obtenerPropiedad("comunicarVentaWeb");
            String []destinos = mail.split(",");
            for (int i=0; i<destinos.length; i++){
                email.enviarEmailSimple(r.obtenerPropiedad("mailVentas"),destinos[i],"","",titulo,mensaje.toString());
            }

        } catch (SQLException e) {
            try {
                conexion.rollbackTransaction();
            } catch (SQLException ex) {
                logger.log(Level.SEVERE,e.getMessage(),ex);
            }
            logger.log(Level.SEVERE,e.getMessage(),e);
            throw new AvwException(e);
        } finally {
            conexion.cerrarConexion();
        }
        return comNumero;

    }

    private static String getNucValor(String tipo) throws SQLException, 
                                                          AvwException {
        ResultSet rs;
        ConexionAvw conexion =  new ConexionAvw();
        StringBuilder sql = new StringBuilder();
        String codigo;
        ArrayList params = new ArrayList();
        int pos=0;
        //Como se si es de tipo A o B??
        try{
            conexion.abrirConexion();
            //Obtengo el codigo con el q debo insertar
            sql.setLength(0); //Limpio la cadena
            sql.append("SELECT nuc_valor ");
            sql.append("FROM ");
            sql.append("numeradores_comprobantes  ");
            sql.append("WHERE ");
            sql.append("NUC_CODIGO ");
            sql.append("LIKE ? ");
            params.add(new BoundParam(++pos, tipo, VARCHAR));
            
            logger.info("Busco el nuc_valor");
            
            rs = conexion.getPreparedStatementResultSet(sql, params);
            logger.info(sql.toString());
            rs.next();
            codigo = Utiles.noNull(rs.getObject(1));

        }catch (SQLException e) {
                logger.log(Level.SEVERE,e.getMessage(),e);
                throw new AvwException(e);
        } finally {
            conexion.cerrarConexion();
        }
         return codigo;
    }

    private static void incrementarNucValor(String tipo) throws SQLException, 
                                                                AvwException {
        StringBuilder sql = new StringBuilder();
        String codigo;
        int pos=0;
        ConexionAvw conexion = new ConexionAvw();
        ArrayList params = new ArrayList();
        try{
            conexion.abrirConexion();
            logger.info("Actualizo la tabla numeradores_comprobantes en uno con el tipo: " + 
                        tipo);
            sql.append("UPDATE NUMERADORES_COMPROBANTES ");
            sql.append("SET nuc_valor = nuc_valor + 1 ");
            sql.append("WHERE nuc_codigo LIKE ? ");
            params.add(new BoundParam(++pos, Utiles.noNull(tipo), VARCHAR));
           
            conexion.executePreparedStatement(sql, params);
        }catch (SQLException e) {
                logger.log(Level.SEVERE,e.getMessage(),e);
                throw new AvwException(e);
        } finally {
            conexion.cerrarConexion();
        }
    }

}
